package de.wiroo.setup.web.common;

import java.util.List;

import org.apache.wicket.event.IEvent;
import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;

import de.stefanocke.roo.wicket.RooStereotype;
import de.wiroo.setup.domain.Whole;

@RooStereotype("wicket.Table")
public abstract class TablePanel<T> extends Panel {

	private static final String TABLE_ID = "table";
	
	private static final long serialVersionUID = 1L;

	protected TablePanel() {
		super("INVALID");
		throw new UnsupportedOperationException(
				"Do not use this constructor since it is only a workaround for ITD issues");
	}

	@Deprecated
	public TablePanel(String id, ISortableDataProvider<T, String> dataProvider) {
		super(id);
		throw new UnsupportedOperationException(
				"Do not use this constructor ");
	}
	
	public TablePanel(String id, IServiceBindings<T, ?> serviceBindings) {
		super(id);
		List<IColumn<T, String>> columns = createColumns();
		columns.add(createActionColumn(serviceBindings.getSingleEntityActions()));
		DataTable<T, String> table = createTable(TABLE_ID, (List<IColumn<T, String>>) columns, serviceBindings.createDataProvider());
		add(table);
		//table.addBottomToolbar(toolbar)
		setOutputMarkupId(true);
	}
	
	@SuppressWarnings("unchecked")
	public DataTable<T, String> getTable(){
		return (DataTable<T, String>) get(TABLE_ID);
	}

	protected DataTable<T, String> createTable(String id, List<IColumn<T, String>> columns, ISortableDataProvider<T, String> dataProvider) {
		return new AjaxFallbackDefaultDataTable<T, String>(id, columns, dataProvider, getRowsPerPage());
	}

	protected int getRowsPerPage() {
		return 10;
	}

	protected abstract List<IColumn<T, String>> createColumns();

	protected IColumn<T, String> createColumn(String propertyExpression, String resourceKey, String sortProperty) {
		return new PropertyColumn<T, String>(new ResourceModel(resourceKey), sortProperty, propertyExpression) {

			private static final long serialVersionUID = 1L;

			@Override
			public boolean isSortable() {
				return TablePanel.this.isSortable() && super.isSortable();
			}
		};
	}

	@SuppressWarnings("serial")
	protected <M> IColumn<T, String> createColumn(final String propertyExpression, String resourceKey, String sortProperty,
			final ComponentFactory<M> cf) {
		return new AbstractColumn<T, String>(new ResourceModel(resourceKey), sortProperty) {
			@Override
			public void populateItem(Item<ICellPopulator<T>> cellItem, String componentId, IModel<T> rowModel) {
				cellItem.add(cf.createComponent(componentId, new PropertyModel<M>(rowModel, propertyExpression)));

			}

			@Override
			public boolean isSortable() {
				return TablePanel.this.isSortable() && super.isSortable();
			}
		};
	}

	protected boolean isSortable() {
		return false;
	}
	
	private IColumn<T, String> createActionColumn(final List<IAction<?, IModel<T>>> list) {
		return new AbstractColumn<T, String>(Model.of("")) {
			@Override
			public void populateItem(Item<ICellPopulator<T>> cellItem, String componentId, IModel<T> rowModel) {
				cellItem.add(createActionPanel(componentId, rowModel,list));
			}

			@Override
			public boolean isSortable() {
				return false;
			}
		};
	}

	protected ActionPanel<T> createActionPanel(String componentId, IModel<T> rowModel, List<IAction<?, IModel<T>>> list) {
		return new ActionPanel<T>(componentId, rowModel).withActions(list).withNavigation(NavigationEvent.DETAILS);
	}
	
	@Override
	public void onEvent(IEvent<?> event) {
		Object payload = event.getPayload();
		if (payload instanceof ActionEvent<?, ?>) {
			ActionEvent<?, ?> actionEvent = (ActionEvent<?, ?>) payload;
			String actionId = actionEvent.getAction().getActionId();
			if ((IServiceBindings.ACTION_ID_SAVE.equals(actionId) || IServiceBindings.ACTION_ID_DELETE  //TODO: Bei updates existierender Objekte nur die zeile refreshen
					.equals(actionId)) && actionEvent.getParam() instanceof IModel<?>) {  //wirklich param?
				IModel<?> actionResult = (IModel<?>) actionEvent.getResult();
				//if (actionResult.getObject().getClass() == getObjectClass()) { //TODO
					
					if (actionEvent.getTarget() != null) {
						actionEvent.getTarget().add(TablePanel.this);
					}
				//}
			}
			event.dontBroadcastDeeper();
		}
	
	}	
	

	/**
	 * Set the visibility of the content of the panel but let the panel itself visible. Useful for Ajax updates, since it allows 
	 * to simply add the TablePanel to the AjaxRequestTarget instead of adding on more div around it.
	 * @param visible
	 */
	public void setInnerVisible(boolean visible){
		getTable().setVisible(visible);
	}
}
